namespace StrongNameRemove
{
    using Asmex.FileViewer;
    using System;
    using System.Collections;
    using System.IO;
    using System.Text;

    internal class Utility
    {
        private const long ASSEMBLY_TABLE_FLAGS_OFFSET = 12L;
        private const int ASSEMBLY_TABLE_FLAGS_VALUE_PUBLICKEY = 1;
        private const long ASSEMBLY_TABLE_PUBLIC_KEY_INDEX_OFFSET = 0x10L;
        private const long CLI_HEADER_FLAGS_OFFSET = 0x10L;
        private const int CLI_HEADER_STRONG_NAME_SIGNATURE_LENGTH = 8;
        private const int COMIMAGE_FLAGS_VALUE_ILONLY = 1;
        private const int COMIMAGE_FLAGS_VALUE_STRONGNAMESIGNED = 8;
        private const long REFERENCE_TABLE_PUBLIC_KEY_OR_TOKEN_OFFSET = 12L;

        private Utility()
        {
        }

        public static string AssemblyFlagToString(uint flag)
        {
            StringBuilder builder = new StringBuilder();
            if ((flag & 1) == 1)
            {
                builder.Append("PublicKey | ");
            }
            if (0 == 0)
            {
                builder.Append("SideBySideCompatible | ");
            }
            if ((flag & 0x30) == 0x30)
            {
                builder.Append("<reserved> | ");
            }
            if ((flag & 0x100) == 0x100)
            {
                builder.Append("Retargetable | ");
            }
            if ((flag & 0x30) == 0x8000)
            {
                builder.Append("EnableJITcompileTracking | ");
            }
            if ((flag & 0x100) == 0x4000)
            {
                builder.Append("DisableJITcompileOptimizer | ");
            }
            if (builder.Length > 0)
            {
                return builder.Remove(builder.Length - 3, 3).ToString();
            }
            return string.Empty;
        }

        public static bool CheckFileExistsAndReadable(string fileName)
        {
            bool flag = false;
            FileStream stream = null;
            try
            {
                if (File.Exists(fileName))
                {
                    stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                    if (stream.CanRead && stream.CanSeek)
                    {
                        flag = true;
                    }
                }
            }
            catch (UnauthorizedAccessException)
            {
                flag = false;
            }
            catch (IOException)
            {
                flag = false;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
            return flag;
        }

        public static bool CheckFileExistsAndWriteable(string fileName)
        {
            bool flag = false;
            FileStream stream = null;
            try
            {
                if (File.Exists(fileName))
                {
                    stream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
                    if (stream.CanWrite)
                    {
                        flag = true;
                    }
                }
            }
            catch (UnauthorizedAccessException)
            {
                flag = false;
            }
            catch (IOException)
            {
                flag = false;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
            return flag;
        }

        public static string CLIHeaderFlagToString(uint flag)
        {
            StringBuilder builder = new StringBuilder();
            if ((flag & 1) == 1)
            {
                builder.Append("COMIMAGE_FLAGS_ILONLY | ");
            }
            if ((flag & 2) == 2)
            {
                builder.Append("COMIMAGE_FLAGS_32BITREQUIRED | ");
            }
            if ((flag & 8) == 8)
            {
                builder.Append("COMIMAGE_FLAGS_STRONGNAMESIGNED | ");
            }
            if ((flag & 0x10000) == 0x10000)
            {
                builder.Append("COMIMAGE_FLAGS_TRACKDEBUGDATA | ");
            }
            if (builder.Length > 0)
            {
                return builder.Remove(builder.Length - 3, 3).ToString();
            }
            return string.Empty;
        }

        public static bool GetAssemblyData(string fileName, ref uint cliHeaderFlag, ref long cliHeaderFlagOffset, ref long strongNameSignatureOffset, ref long publicKeyIndexOffset, ref long publicKeyOffset, ref uint assemblyFlag, ref long assemblyFlagOffset, ref string compiledRuntimeVersion, ref ArrayList assemblyReferences, ref int blobIndexSize)
        {
            FileStream input = null;
            cliHeaderFlag = 0;
            cliHeaderFlagOffset = 0L;
            strongNameSignatureOffset = 0L;
            publicKeyIndexOffset = 0L;
            publicKeyOffset = 0L;
            compiledRuntimeVersion = string.Empty;
            assemblyFlag = 0;
            assemblyFlagOffset = 0L;
            assemblyReferences.Clear();
            try
            {
                if (File.Exists(fileName))
                {
                    input = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                    BinaryReader reader = new BinaryReader(input);
                    MModule module = new MModule(reader);
                    try
                    {
                        if (module.ModHeaders.COR20Header == null)
                        {
                            return false;
                        }
                        cliHeaderFlag = module.ModHeaders.COR20Header.Flags;
                        cliHeaderFlagOffset = module.ModHeaders.COR20Header.Start + 0x10L;
                        strongNameSignatureOffset = (module.ModHeaders.COR20Header.StrongNameSignature.Rva == 0) ? 0L : module.ModHeaders.COR20Header.StrongNameSignature.Start;
                        compiledRuntimeVersion = module.ModHeaders.MetaDataHeaders.StorageSigAndHeader.VersionString.Replace("\0", string.Empty);
                        blobIndexSize = module.MDTables.GetBlobIndexSize();
                        long end = module.ModHeaders.MetaDataTableHeader.End;
                        for (int i = 0; i < 0x20; i++)
                        {
                            end += module.MDTables.Tables[i].RawData.Length;
                        }
                        Table table = module.MDTables.GetTable(Types.Assembly);
                        if (table.Count > 0)
                        {
                            if (table[0][6].RawData == 0)
                            {
                                publicKeyOffset = 0L;
                            }
                            else
                            {
                                publicKeyOffset = (module.BlobHeap.Start + table[0][6].RawData) + ((long) ((ulong) 1L));
                            }
                            assemblyFlag = (uint) table[0][5].Data;
                            if (end > 0L)
                            {
                                publicKeyIndexOffset = end + 0x10L;
                                assemblyFlagOffset = end + 12L;
                            }
                        }
                        long num3 = module.ModHeaders.MetaDataTableHeader.End;
                        for (int j = 0; j < 0x23; j++)
                        {
                            num3 += module.MDTables.Tables[j].RawData.Length;
                        }
                        if (num3 > 0L)
                        {
                            Table table2 = module.MDTables.GetTable(Types.AssemblyRef);
                            if (table2.Count > 0)
                            {
                                for (int k = 0; k < table2.Count; k++)
                                {
                                    AssemblyReference reference = new AssemblyReference(table2[k][6].Data.ToString(), string.Concat(new object[] { table2[k][0].Data, ".", table2[k][1].Data, ".", table2[k][2].Data, ".", table2[k][3].Data }), table2[k][5].Data.ToString(), num3 + (k * table2.RowSize));
                                    assemblyReferences.Add(reference);
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                    finally
                    {
                        reader.Close();
                    }
                }
            }
            catch (UnauthorizedAccessException)
            {
                return false;
            }
            catch (IOException)
            {
                return false;
            }
            finally
            {
                if (input != null)
                {
                    input.Close();
                }
            }
            return true;
        }

        public static bool IsAssemblyStrongSigned(uint cliHeaderFlag)
        {
            return (cliHeaderFlag >= 8);
        }

        public static bool PatchAssemblyStrongSigning(string fileName, uint cliHeaderFlag, long cliHeaderFlagOffset, long strongNameSignatureOffset, long publicKeyIndexOffset, uint assemblyFlag, long assemblyFlagOffset, int blobIndexSize)
        {
            if (CheckFileExistsAndWriteable(fileName))
            {
                FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
                if (cliHeaderFlagOffset > 0L)
                {
                    byte[] pattern = new byte[] { (byte) (cliHeaderFlag - 8) };
                    WritePattern(fileStream, pattern, cliHeaderFlagOffset);
                }
                if (strongNameSignatureOffset > 0L)
                {
                    byte[] buffer2 = new byte[8];
                    for (short i = 0; i < 8; i = (short) (i + 1))
                    {
                        buffer2[i] = 0;
                    }
                    WritePattern(fileStream, buffer2, strongNameSignatureOffset);
                }
                if (publicKeyIndexOffset > 0L)
                {
                    byte[] buffer3 = new byte[blobIndexSize];
                    for (short j = 0; j < blobIndexSize; j = (short) (j + 1))
                    {
                        buffer3[j] = 0;
                    }
                    WritePattern(fileStream, buffer3, publicKeyIndexOffset);
                }
                if (assemblyFlagOffset > 0L)
                {
                    byte[] buffer4 = new byte[] { (byte) (assemblyFlag - 1) };
                    WritePattern(fileStream, buffer4, assemblyFlagOffset);
                }
                fileStream.Flush();
                fileStream.Close();
                return true;
            }
            return false;
        }

        public static bool PatchReference(string fileName, long referenceOffset, int blobIndexSize)
        {
            if (CheckFileExistsAndWriteable(fileName))
            {
                FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
                if (referenceOffset > 0L)
                {
                    byte[] pattern = new byte[blobIndexSize];
                    for (short i = 0; i < blobIndexSize; i = (short) (i + 1))
                    {
                        pattern[i] = 0;
                    }
                    WritePattern(fileStream, pattern, referenceOffset + 12L);
                }
                fileStream.Flush();
                fileStream.Close();
                return true;
            }
            return false;
        }

        public static void WritePattern(FileStream fileStream, byte[] pattern, long position)
        {
            if (position <= ((fileStream.Length - pattern.Length) + 1L))
            {
                fileStream.Position = position;
                for (int i = 0; i < pattern.Length; i++)
                {
                    fileStream.WriteByte(pattern[i]);
                }
            }
        }
    }
}
